require '../lib/vector'
require '../lib/content'

class Cluster < Array
  attr_accessor :centroid
  attr_accessor :data

  def initialize(centroid)
    @centroid = centroid
    super()
  end

  def update_centroid
    # puts "\nupdate centroid"
    # puts "old centroid: #{@centroid}"
    old_centroid = @centroid
    if size > 1
      i=0
      distances = Array.new
      self.each do |current_vector|
        distances[i] = 0
        self.each { |vector| distances[i] += current_vector.distance(vector) }
        i += 1
      end
      min = distances.min
      # puts "#{distances.inspect} -> min = #{min}"

      @centroid = self[distances.index(min)]

    end
    # puts "new centroid: #{@centroid}"
    # puts "cluster size: #{size}"

    return (not (old_centroid == @centroid))
  end

  def distance(cluster)
    @centroid.distance(cluster.centroid)
  end

  def merge(cluster)
    self << cluster.data
    update_centroid
  end
end

class KClusterer
  attr_reader :clusters

  def initialize(dataset, k)
    @data = dataset
    @num_clusters = k
    @clusters = []
  end
end

class Kmeans < KClusterer
  def run
    @clusters = []
    @num_clusters.times {|i| @clusters << Cluster.new(@data[i]) }
  
    puts "Creating clusters..."
    5.times do
      # Put each data item into the cluster whose center it is closest too.
      @clusters.map! {|c| Cluster.new(c.centroid) }
      
      @data.each do |item|
        @clusters.min {|a, b| a.centroid.distance(item) <=> b.centroid.distance(item) } << item        
      end
      
      @clusters.each_with_index do |item, index|
        puts "cluster #{index + 1}: #{item.size} documents"
      end
      
      break unless @clusters.map {|c| c.update_centroid }.detect {|i| i}
    end

    self
  end
end
